/****************************************************************************************
**  File: Material.hpp
**  Author: Asteroth
**  Date: 5-mag-2009
****************************************************************************************/

#ifndef __MATERIAL_HPP__
#define __MATERIAL_HPP__

class Material: public estd::Serializable {
public:
	float ambient[4];
	float diffuse[4];
	float specular[4];
	float emission[4];
	float shininess;

	Material() {
		ambient[0] = ambient[1] = ambient[2] = 0.2;
		diffuse[0] = diffuse[1] = diffuse[2] = 0.8;
		specular[0] = specular[1] = specular[2] = 0.0;
		emission[0] = emission[1] = emission[2] = 0.0;
		ambient[3] = diffuse[3] = specular[3] = emission[3] = 1.0;
		shininess = 0.0;
	}

	Material(const Material &mat) {
		ambient[0] = mat.ambient[0];
		ambient[1] = mat.ambient[1];
		ambient[2] = mat.ambient[2];
		ambient[3] = mat.ambient[3];
		diffuse[0] = mat.diffuse[0];
		diffuse[1] = mat.diffuse[1];
		diffuse[2] = mat.diffuse[2];
		diffuse[3] = mat.diffuse[3];
		specular[0] = mat.specular[0];
		specular[1] = mat.specular[1];
		specular[2] = mat.specular[2];
		specular[3] = mat.specular[3];
		emission[0] = mat.emission[0];
		emission[1] = mat.emission[1];
		emission[2] = mat.emission[2];
		emission[3] = mat.emission[3];
		shininess = mat.shininess;
	}

	Material(const core::Quaternion &ambient, const core::Quaternion &diffuse, const core::Quaternion &specular, const core::Quaternion &emission, float shininess) {
		this->ambient[0] = ambient.X;
		this->ambient[1] = ambient.Y;
		this->ambient[2] = ambient.Z;
		this->ambient[3] = ambient.W;
		this->diffuse[0] = diffuse.X;
		this->diffuse[1] = diffuse.Y;
		this->diffuse[2] = diffuse.Z;
		this->diffuse[3] = diffuse.W;
		this->specular[0] = specular.X;
		this->specular[1] = specular.Y;
		this->specular[2] = specular.Z;
		this->specular[3] = specular.W;
		this->emission[0] = emission.X;
		this->emission[1] = emission.Y;
		this->emission[2] = emission.Z;
		this->emission[3] = emission.W;
		this->shininess = shininess;
	}

	inline Material &operator = (const Material &mat) {
		ambient[0] = mat.ambient[0];
		ambient[1] = mat.ambient[1];
		ambient[2] = mat.ambient[2];
		ambient[3] = mat.ambient[3];
		diffuse[0] = mat.diffuse[0];
		diffuse[1] = mat.diffuse[1];
		diffuse[2] = mat.diffuse[2];
		diffuse[3] = mat.diffuse[3];
		specular[0] = mat.specular[0];
		specular[1] = mat.specular[1];
		specular[2] = mat.specular[2];
		specular[3] = mat.specular[3];
		emission[0] = mat.emission[0];
		emission[1] = mat.emission[1];
		emission[2] = mat.emission[2];
		emission[3] = mat.emission[3];
		shininess = mat.shininess;

		return *this;
	}

	inline void activate(GLenum face = GL_FRONT_AND_BACK) {
		glMaterialfv(face, GL_AMBIENT, ambient);
		glMaterialfv(face, GL_DIFFUSE, diffuse);
		glMaterialfv(face, GL_SPECULAR, specular);
		glMaterialfv(face, GL_EMISSION, emission);
		glMaterialf(face, GL_SHININESS, shininess);
	}

	estd::XMLNode serialize(estd::String id = "") {
		estd::XMLNode node;

		node = estd::XMLNode::createXMLTopNode("Material");
		if (id!="")
			node.addAttribute("Id", id);

		node.addChild("Shininess").addText(estd::String::fromFloat(shininess));

		estd::XMLNode sub = node.addChild("Ambient");
		sub.addChild("R").addText(estd::String::fromFloat(ambient[0]));
		sub.addChild("G").addText(estd::String::fromFloat(ambient[1]));
		sub.addChild("B").addText(estd::String::fromFloat(ambient[2]));
		sub.addChild("A").addText(estd::String::fromFloat(ambient[3]));

		sub = node.addChild("Diffuse");
		sub.addChild("R").addText(estd::String::fromFloat(diffuse[0]));
		sub.addChild("G").addText(estd::String::fromFloat(diffuse[1]));
		sub.addChild("B").addText(estd::String::fromFloat(diffuse[2]));
		sub.addChild("A").addText(estd::String::fromFloat(diffuse[3]));

		sub = node.addChild("Specular");
		sub.addChild("R").addText(estd::String::fromFloat(specular[0]));
		sub.addChild("G").addText(estd::String::fromFloat(specular[1]));
		sub.addChild("B").addText(estd::String::fromFloat(specular[2]));
		sub.addChild("A").addText(estd::String::fromFloat(specular[3]));

		sub = node.addChild("Emission");
		sub.addChild("R").addText(estd::String::fromFloat(emission[0]));
		sub.addChild("G").addText(estd::String::fromFloat(emission[1]));
		sub.addChild("B").addText(estd::String::fromFloat(emission[2]));
		sub.addChild("A").addText(estd::String::fromFloat(emission[3]));

		return node;
	}

	bool deserialize(const estd::XMLNode &material) {
		if (material.isEmpty())
			return false;

		estd::XMLNode sub = material.getChildNode("Shininess");
		if (sub.isEmpty())
			return false;
		shininess = estd::String(sub.getText()).toFloat();

		sub = material.getChildNode("Ambient");
		if (sub.isEmpty())
			return false;
		ambient[0] = estd::String(sub.getChildNode("R").getText()).toFloat();
		ambient[1] = estd::String(sub.getChildNode("G").getText()).toFloat();
		ambient[2] = estd::String(sub.getChildNode("B").getText()).toFloat();
		ambient[3] = estd::String(sub.getChildNode("A").getText()).toFloat();

		sub = material.getChildNode("Diffuse");
		if (sub.isEmpty())
			return false;
		diffuse[0] = estd::String(sub.getChildNode("R").getText()).toFloat();
		diffuse[1] = estd::String(sub.getChildNode("G").getText()).toFloat();
		diffuse[2] = estd::String(sub.getChildNode("B").getText()).toFloat();
		diffuse[3] = estd::String(sub.getChildNode("A").getText()).toFloat();

		sub = material.getChildNode("Specular");
		if (sub.isEmpty())
			return false;
		specular[0] = estd::String(sub.getChildNode("R").getText()).toFloat();
		specular[1] = estd::String(sub.getChildNode("G").getText()).toFloat();
		specular[2] = estd::String(sub.getChildNode("B").getText()).toFloat();
		specular[3] = estd::String(sub.getChildNode("A").getText()).toFloat();

		sub = material.getChildNode("Emission");
		if (sub.isEmpty())
			return false;
		emission[0] = estd::String(sub.getChildNode("R").getText()).toFloat();
		emission[1] = estd::String(sub.getChildNode("G").getText()).toFloat();
		emission[2] = estd::String(sub.getChildNode("B").getText()).toFloat();
		emission[3] = estd::String(sub.getChildNode("A").getText()).toFloat();

		return true;
	}
};

#endif
